package biz

import (
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"reflect"
	"strconv"
	"sync"
	"xiaoniu-job/internal/cache"
	"xiaoniu-job/internal/config"
	"xiaoniu-job/internal/job"
	"xiaoniu-job/pkg"
	"xiaoniu-job/pkg/util"
)

// 任务队列容量为10
var queue = make(chan *pkg.ClientTaskRequest, 10)

// 控制是否继续消费任务
var stop = false

// 控制是否有任务在执行
var wg sync.WaitGroup

// CompleteChan 控制最终程序是否停止的channel
var CompleteChan = make(chan bool, 1)

// 将一个任务放入到任务队列
func produce(request *pkg.ClientTaskRequest) bool {
	if stop {
		return false
	}
	queue <- request
	return true
}

// StartConsumer 消费者开始工作
func StartConsumer() {
	for {
		if stop {
			break
		}
		val, ok := <-queue
		if ok {
			go doJob(val)
		} else {
			break
		}
	}
}

func RunOnce(request *pkg.ClientTaskRequest) (res string, err error) {
	defer func() {
		if p := recover(); p != nil {
			log.Println("调度任务时出错：", p)
			err = errors.New("调度任务时出错")
		}
	}()
	if request.TaskId == 0 {
		return "任务Id为空，调度失败", nil
	}
	if request.TaskLabel == "" {
		return "任务标识为空，调度失败", nil
	}
	if _, ok := job.LocalTaskMap[request.TaskLabel]; !ok {
		return "该任务没有注册，无法执行", nil
	}
	// 将任务放入任务队列
	b := produce(request)
	if b {
		return "调度成功", nil
	}
	return "调度失败", nil
}

// 调用具体的任务函数
func doJob(request *pkg.ClientTaskRequest) {
	defer wg.Done()
	wg.Add(1)
	// 任务标识即为本地需要执行的方法名
	f := reflect.ValueOf(job.LocalTaskMap[request.TaskLabel])
	in := make([]reflect.Value, 2)
	in[0] = f
	in[1] = reflect.ValueOf(request)

	reflect.ValueOf(job.CommonLogic).Call(in)
	return
}

func GetLog(request *pkg.ClientLogRequest) (pkg.ClientTaskResult, error) {
	s, ok := cache.CACHE[request.TaskId]
	if ok {
		return s, nil
	}
	// 没有找到
	return pkg.ClientTaskResult{}, errors.New("内存中找不到了！")
}

func QueryLocalLog(request *pkg.ClientLogRequest) (res string, err error) {
	defer func() {
		if p := recover(); p != nil {
			fmt.Println("读取日志文件时出错：", p)
			res = "找不到日志文件"
		}
	}()
	file := config.ClientRation.LogPath + "/task/" + strconv.FormatUint(request.TaskId, 10) + ".log"

	if exists, err := util.FileAndDirIsExistCommonService(file); !exists {
		return "日志文件不存在", err
	}

	data, er := ioutil.ReadFile(file)
	if er != nil {
		fmt.Fprintf(os.Stderr, "error reading file: %v\n", er)
		return "读取错误", er
	}
	return string(data), nil
}

// StopConsumer 停止接收服务端的调度请求
func StopConsumer() {
	stop = true
	close(queue)
	// 如果还有任务在执行的话，会阻塞在这里，没有的话直接就是一个空操作，继续往下执行
	wg.Wait()
	fmt.Println("所有任务已经全部执行完成，程序马上就要退出了！")
	CompleteChan <- true
}
